home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / TIFF / DEPTHDOF.C next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  13.0 KB  |  562 lines

  1.  
  2. /**
  3.  
  4.    depthdof.c: depth-of-field simulator using stencilled convolutions
  5.       Jon Brandt, 1/97
  6.       converted to GLUT and libtiff by Mark Kilgard, 4/97
  7.  
  8.    Compile with:
  9.  
  10.      cc -o depthdof depthdof.c -ltiff -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm
  11.     
  12.  **/
  13.  
  14. #include <GL/glut.h>
  15.  
  16. #include <tiffio.h>
  17.  
  18. #include <assert.h>
  19. #include <math.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <strings.h>
  23. #include <unistd.h>
  24.  
  25. #define FALSE 0
  26. #define TRUE 1
  27.  
  28. const char *DefaultImage = "face.tif";
  29. int winWidth = 512, winHeight = 512;
  30. char *pixels = NULL;
  31. int stencilMax;
  32. int kSize = 5;
  33. int kRadius = 5 / 2;
  34. float sharpness = -1.5;
  35. float kernel[] =
  36. {.05, .1, .7, .1, .05};
  37. int passes = 5;
  38. int contour = 0;
  39. char focus = 160;
  40. float spread = 1;
  41. int focusPending = FALSE;
  42. int splitScreen = FALSE;
  43. int smoothDepth = FALSE;
  44. int frame = 0;
  45. int running = TRUE;
  46. int cursor_x, cursor_y;
  47. int multisample, hasConvolve = 0;
  48.  
  49. TIFFRGBAImage img;
  50. uint32 *raster;
  51. uint32 *texture;
  52. size_t npixels;
  53. int tw, th;
  54. int angle;
  55.  
  56. int hasABGR = 0;
  57.  
  58. void drawFrame(int frame);
  59. void initScene(int argc, char *argv[]);
  60. void drawScene(int frame);
  61. void drawObject(float numRep);
  62. void changePassCount(int delta);
  63. void setBlurMap(void);
  64. void setKernel(void);
  65. void resize(int w, int h);
  66. void toggle(int *param, char *msg);
  67.  
  68. void
  69. redraw(void)
  70. {
  71.   drawFrame(frame);
  72. }
  73.  
  74. void
  75. idle(void)
  76. {
  77.   frame++;
  78.   glutPostRedisplay();
  79. }
  80.  
  81. void
  82. visible(int vis)
  83. {
  84.   if (vis == GLUT_VISIBLE)
  85.     glutIdleFunc(idle);
  86.   else
  87.     glutIdleFunc(NULL);
  88. }
  89.  
  90. /* ARGSUSED1 */
  91. void
  92. keyboard(unsigned char c, int x, int y)
  93. {
  94.   switch (c) {
  95.   case 27:
  96.     exit(0);
  97.     break;
  98.   case 'g':
  99.     running = !running;
  100.     if (running) {
  101.       glutIdleFunc(idle);
  102.     } else {
  103.       glutIdleFunc(NULL);
  104.     }
  105.     break;
  106.   case 'c':
  107.     toggle(&contour, NULL);
  108.     glutPostRedisplay();
  109.     break;
  110.   case 's':
  111.     toggle(&splitScreen, NULL);
  112.     glutPostRedisplay();
  113.     break;
  114.   case 'd':
  115.     toggle(&smoothDepth, "depth smoothing");
  116.     glutPostRedisplay();
  117.     break;
  118.   case ' ':
  119.     frame++;
  120.     glutPostRedisplay();
  121.     break;
  122.   case '-':
  123.     frame--;
  124.     glutPostRedisplay();
  125.     break;
  126.   case 'p':
  127.     changePassCount(1);
  128.     glutPostRedisplay();
  129.     break;
  130.   case 'P':
  131.     changePassCount(-1);
  132.     glutPostRedisplay();
  133.     break;
  134.   case 'a':
  135.     spread *= 1 / 1.2;
  136.     setBlurMap();
  137.     glutPostRedisplay();
  138.     break;
  139.   case 'A':
  140.     spread *= 1.2;
  141.     setBlurMap();
  142.     glutPostRedisplay();
  143.     break;
  144.   case 'k':
  145.     sharpness *= 1 / 1.2;
  146.     printf("sharpness == %g\n", sharpness);
  147.     setKernel();
  148.     glutPostRedisplay();
  149.     break;
  150.   case 'K':
  151.     sharpness *= 1.2;
  152.     printf("sharpness == %g\n", sharpness);
  153.     setKernel();
  154.     glutPostRedisplay();
  155.     break;
  156.   }
  157. }
  158.  
  159. void
  160. mouse(int b, int state, int x, int y)
  161. {
  162.   if (b == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
  163.     cursor_x = x;
  164.     cursor_y = winHeight - y;
  165.     focusPending = TRUE;
  166.     glutPostRedisplay();
  167.   }
  168. }
  169.  
  170. void
  171. main(int argc, char *argv[])
  172. {
  173.   int c;
  174.  
  175.   glutInit(&argc, argv);
  176.  
  177.   while ((c = getopt(argc, argv, "p:")) != -1) {
  178.     switch (c) {
  179.     case 'p':
  180.       passes = atoi(optarg);
  181.       break;
  182.     }
  183.   }
  184.  
  185.   glutInitDisplayString("samples depth stencil~8 double");
  186.   glutCreateWindow("Depth of Field via Depth-varying Convolve");
  187.   initScene(argc - optind + 1, argv + optind - 1);
  188.   changePassCount(0);
  189.   printf("Key commands:\n");
  190.   printf("          c: show/hide outer blur limit\n");
  191.   printf("          g: toggle free running animation\n");
  192.   printf("          s: toggle split-screen\n");
  193.   printf("          d: toggle depth smoothing\n");
  194.   printf("    <space>: step one frame forward\n");
  195.   printf("          -: step one frame backward\n");
  196.   printf("       p(P): increment(decrement) number of passes\n");
  197.   printf("       a(A): narrow(widen) lens aperture\n");
  198.   printf("       k(K): increase(decrease) kernel bluriness\n");
  199.   printf("      <esc>: exit\n");
  200.   printf("Mouse clicking changes focus depth.\n");
  201.  
  202.   glutVisibilityFunc(visible);
  203.   glutKeyboardFunc(keyboard);
  204.   glutMouseFunc(mouse);
  205.   glutDisplayFunc(redraw);
  206.   glutReshapeFunc(resize);
  207.  
  208.   multisample = glutGet(GLUT_WINDOW_NUM_SAMPLES) > 0;
  209.   if (glutExtensionSupported("GL_EXT_convolution")) {
  210.     hasConvolve = 1;
  211.   } else {
  212.     while (glGetError() != GL_NO_ERROR);  /* Clear any OpenGL errors. */
  213.  
  214.     /* The following glDisable would be a no-op whether done on a freshly
  215.        initialized OpenGL context whether convolution is supported or not.
  216.        The only difference should be an OpenGL error should be reported if
  217.        the GL_CONVOLUTION_2D_EXT is not understood (ie, convolution is not
  218.        supported at all). */
  219.     glDisable(GL_CONVOLUTION_2D_EXT);
  220.  
  221.     if (glGetError() == GL_NO_ERROR) {
  222.       /* RealityEngine only partially implements the convolve extension and
  223.          hence does not advertise the extension in its extension string (See
  224.          MACHINE DEPENDENCIES section of the glConvolutionFilter2DEXT man
  225.          page). We limit this program to use only the convolve functionality
  226.          supported by RealityEngine so we test if OpenGL lets us enable
  227.          convolution without an error (the indication that convolution is
  228.          partially supported). */
  229.       hasConvolve = 1;
  230.     }
  231.     /* Clear any further OpenGL errors (hopefully there should have only been
  232.        one or zero though). */
  233.     while (glGetError() != GL_NO_ERROR);
  234.   }
  235.  
  236.   if (!hasConvolve) {
  237.     printf("\nTHIS PROGRAM IS NOT VERY INTERESTING WITHOUT THE OPENGL CONVOLVUTION EXTENSION\n\n");
  238.   }
  239.  
  240.   glutMainLoop();
  241. }
  242.  
  243. void
  244. initScene(int argc, char *argv[])
  245. {
  246.   TIFF *tif;
  247.   char emsg[1024];
  248.   int bits;
  249.   const char *fname = argc > 1 ? argv[1] : DefaultImage;
  250.  
  251.   glViewport(0, 0, winWidth, winHeight);
  252.  
  253.   glEnable(GL_TEXTURE_2D);
  254.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  255.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  256.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  257.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  258.   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  259.  
  260.   tif = TIFFOpen(fname, "r");
  261.   if (tif == NULL) {
  262.     fprintf(stderr, "Problem showing %s\n", fname);
  263.     exit(1);
  264.   }
  265.   if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
  266.     npixels = img.width * img.height;
  267.     raster = (uint32 *) _TIFFmalloc((long) (npixels * sizeof(uint32)));
  268.     if (raster != NULL) {
  269.       if (TIFFRGBAImageGet(&img, raster, img.width, img.height) == 0) {
  270.         TIFFError(fname, emsg);
  271.         exit(1);
  272.       }
  273.     }
  274.     TIFFRGBAImageEnd(&img);
  275.   } else {
  276.     TIFFError(fname, emsg);
  277.     exit(1);
  278.   }
  279.  
  280. #ifdef GL_EXT_abgr
  281.   if (glutExtensionSupported("GL_EXT_abgr"))
  282.     hasABGR = 1;
  283. #else
  284.   hasABGR = 0;
  285. #endif
  286.  
  287.   /* If cannot directly display ABGR format, we need to reverse the component
  288.      ordering in each pixel. :-( */
  289.   if (!hasABGR) {
  290.     int i;
  291.  
  292.     for (i = 0; i < npixels; i++) {
  293.       register unsigned char *cp = (unsigned char *) &raster[i];
  294.       int t;
  295.  
  296.       t = cp[3];
  297.       cp[3] = cp[0];
  298.       cp[0] = t;
  299.       t = cp[2];
  300.       cp[2] = cp[1];
  301.       cp[1] = t;
  302.     }
  303.   }
  304.   /* OpenGL's default unpack (and pack) alignment is 4.  In the case of the
  305.      data returned by libtiff which is already aligned on 32-bit boundaries,
  306.      setting the pack to 1 isn't strictly necessary. */
  307.   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  308.  
  309.   tw = 1 << (int) ceil(log((float) img.width) / log(2.0));
  310.   th = 1 << (int) ceil(log((float) img.height) / log(2.0));
  311.   if (tw > 512)
  312.     tw = 512;
  313.   if (th > 512)
  314.     th = 512;
  315.   texture = (uint32 *) malloc(sizeof(GLubyte) * 4 * tw * th);
  316.  
  317. #ifdef GL_EXT_abgr
  318. #define APPROPRIATE_FORMAT (hasABGR ? GL_ABGR_EXT : GL_RGBA)
  319. #else
  320. #define APPROPRIATE_FORMAT GL_RGBA
  321. #endif
  322.  
  323.   gluScaleImage(APPROPRIATE_FORMAT,
  324.     (int) img.width, (int) img.height, GL_UNSIGNED_BYTE, raster,
  325.     tw, th, GL_UNSIGNED_BYTE, texture);
  326.   _TIFFfree(raster);
  327.  
  328.   if (gluBuild2DMipmaps(GL_TEXTURE_2D, 4, tw, th,
  329.       APPROPRIATE_FORMAT, GL_UNSIGNED_BYTE, texture)) {
  330.     fprintf(stderr, "couldn't build mip map");
  331.     exit(1);
  332.   }
  333.   glGetIntegerv(GL_STENCIL_BITS, &bits);
  334.   stencilMax = (1 << bits) - 1;
  335.   printf("stencil max = %d\n", stencilMax);
  336.  
  337.   setBlurMap();
  338.   setKernel();
  339.  
  340.   glDrawBuffer(GL_BACK);
  341.   glReadBuffer(GL_BACK);
  342.   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  343.  
  344.   glLineStipple(4, 0xaaaa);
  345.   glEnable(GL_LINE_STIPPLE);
  346.   pixels = realloc(pixels, (winWidth + 4) * (winHeight + 4));
  347. }
  348.  
  349. void
  350. drawFrame(int frame)
  351. {
  352.   int pass;
  353.   int activeWidth = splitScreen ? winWidth / 2 : winWidth;
  354.  
  355.   glEnable(GL_DEPTH_TEST);
  356.   glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  357.  
  358.   glMatrixMode(GL_PROJECTION);
  359.   glLoadIdentity();
  360.   glFrustum(-1, 1, -1, 1, 1.5, 20);
  361.  
  362.   glMatrixMode(GL_MODELVIEW);
  363.   glLoadIdentity();
  364.  
  365. #ifdef GL_MULTISAMPLE_SGIS
  366.   if (multisample)
  367.     glEnable(GL_MULTISAMPLE_SGIS);
  368. #endif
  369.   drawScene(frame);
  370. #ifdef GL_MULTISAMPLE_SGIS
  371.   if (multisample)
  372.     glDisable(GL_MULTISAMPLE_SGIS);
  373. #endif
  374.  
  375.   if (passes > 0) {
  376.     glDisable(GL_TEXTURE_2D);
  377.     glDisable(GL_DEPTH_TEST);
  378.     glMatrixMode(GL_PROJECTION);
  379.     glLoadIdentity();
  380.     glOrtho(0, winWidth, 0, winHeight, -1, 1);
  381.     glReadPixels(0, 0, activeWidth, winHeight, GL_DEPTH_COMPONENT,
  382.       GL_UNSIGNED_BYTE, pixels);
  383.  
  384.     if (focusPending) {
  385.       glReadPixels(cursor_x, cursor_y, 1, 1, GL_DEPTH_COMPONENT,
  386.         GL_UNSIGNED_BYTE, &focus);
  387.       printf("focussing on depth == %d\n", focus);
  388.       setBlurMap();
  389.       focusPending = FALSE;
  390.     }
  391.     if (smoothDepth && hasConvolve) {
  392. #ifdef GL_EXT_convolution
  393.       /* convolve the depth map into alpha and read it back */
  394.       glEnable(GL_SEPARABLE_2D_EXT);
  395.       glRasterPos2f(kRadius, kRadius);
  396.       glColorMask(0, 0, 0, 1);
  397.       glDrawPixels(activeWidth, winHeight, GL_ALPHA,
  398.         GL_UNSIGNED_BYTE, pixels);
  399.       glColorMask(1, 1, 1, 1);
  400.       glDisable(GL_SEPARABLE_2D_EXT);
  401.       glReadPixels(0, 0, activeWidth, winHeight, GL_ALPHA,
  402.         GL_UNSIGNED_BYTE, pixels);
  403. #endif
  404.     }
  405.     glRasterPos2f(0, 0);
  406.     glPixelTransferi(GL_MAP_STENCIL, GL_TRUE);
  407.     glDrawPixels(activeWidth, winHeight, GL_STENCIL_INDEX,
  408.       GL_UNSIGNED_BYTE, pixels);
  409.  
  410.     glPixelTransferi(GL_MAP_STENCIL, GL_FALSE);
  411.     glEnable(GL_STENCIL_TEST);
  412.  
  413. #ifdef GL_EXT_convolution
  414.     if (hasConvolve) {
  415.       glEnable(GL_SEPARABLE_2D_EXT);
  416.       for (pass = 0; pass < passes; pass++) {
  417.         glStencilFunc(GL_LEQUAL, (pass + 1), 255);
  418.         glRasterPos2f(kRadius, kRadius);
  419.         glCopyPixels(0, 0, activeWidth, winHeight, GL_COLOR);
  420.       }
  421.       glDisable(GL_SEPARABLE_2D_EXT);
  422.     }
  423. #endif
  424.  
  425.     if (contour) {
  426.       /* mark edge of in-focus region with green contour */
  427.       glStencilFunc(GL_EQUAL, pass, 255);
  428.       glColor3f(0, 1, 0);
  429.       glBegin(GL_TRIANGLE_STRIP);
  430.       glVertex2f(0, 0);
  431.       glVertex2f(0, winHeight);
  432.       glVertex2f(winWidth, 0);
  433.       glVertex2f(winWidth, winHeight);
  434.       glEnd();
  435.     }
  436.     glDisable(GL_STENCIL_TEST);
  437.  
  438.     if (splitScreen) {
  439.       /* yellow divider line */
  440.       glColor3f(1, 1, 0);
  441.       glBegin(GL_LINE_STRIP);
  442.       glVertex2f(activeWidth, 0);
  443.       glVertex2f(activeWidth, winHeight);
  444.       glEnd();
  445.     }
  446.   }
  447.   glutSwapBuffers();
  448. }
  449.  
  450. void
  451. drawScene(int frame)
  452. {
  453.   glPushMatrix();
  454.   glTranslatef(0, 0, -18);
  455.   glDisable(GL_TEXTURE_2D);
  456.   glBegin(GL_TRIANGLE_STRIP);
  457.   glColor3ub(40, 0, 140);
  458.   glVertex2f(-15, -15);
  459.   glVertex2f(15, -15);
  460.   glColor3ub(52, 202, 226);
  461.   glVertex2f(-15, 15);
  462.   glVertex2f(15, 15);
  463.   glEnd();
  464.   glPopMatrix();
  465.  
  466.   glPushMatrix();
  467.   glTranslatef(0, -1, 0);
  468.   glScalef(20, 20, 20);
  469.   glRotatef(90, 1, 0, 0);
  470.   drawObject(20);
  471.   glPopMatrix();
  472.  
  473.   glPushMatrix();
  474.   glTranslatef(0, 0, -5 + 3 * sinf(frame * M_PI / 180));
  475.   glRotatef(frame * 3, 0, 1, 0);
  476.   drawObject(1);
  477.   glPopMatrix();
  478.  
  479.   glPushMatrix();
  480.   glTranslatef(cosf(frame * M_PI / 120), 0, -6 + 4 * sinf(frame * M_PI / 210));
  481.   glRotatef(frame * 3, 1, 0, cosf(frame * M_PI / 360));
  482.   drawObject(1);
  483.   glPopMatrix();
  484.  
  485.   glPushMatrix();
  486.   glTranslatef(0, 0, -5 + 3 * sinf(frame * M_PI / 300));
  487.   drawObject(1);
  488.   glPopMatrix();
  489. }
  490.  
  491. void
  492. drawObject(float n)
  493. {
  494.   glEnable(GL_TEXTURE_2D);
  495.   glColor3f(1, 1, 1);
  496.   glBegin(GL_TRIANGLE_STRIP);
  497.   glTexCoord2f(0, 0);
  498.   glVertex2f(-.5, -.5);
  499.   glTexCoord2f(n, 0);
  500.   glVertex2f(.5, -.5);
  501.   glTexCoord2f(0, n);
  502.   glVertex2f(-.5, .5);
  503.   glTexCoord2f(n, n);
  504.   glVertex2f(.5, .5);
  505.   glEnd();
  506. }
  507.  
  508. void
  509. setBlurMap(void)
  510. {
  511.   int i;
  512.   unsigned short blur[256];
  513.  
  514.   for (i = 0; i < 256; i++) {
  515.     float del = (i - focus) / 255.;
  516.     del *= del * spread * stencilMax;
  517.     blur[i] = del < stencilMax ? del : stencilMax;
  518.   }
  519.   glPixelMapusv(GL_PIXEL_MAP_S_TO_S, 256, blur);
  520. }
  521.  
  522. void
  523. setKernel(void)
  524. {
  525. #ifdef GL_EXT_convolution
  526.   float s1 = expf(sharpness), s2 = expf(2 * sharpness);
  527.   kernel[0] = kernel[4] = s2;
  528.   kernel[1] = kernel[3] = s1;
  529.   kernel[2] = 1 - 2 * (s1 + s2);
  530.   glSeparableFilter2DEXT(GL_SEPARABLE_2D_EXT, GL_LUMINANCE,
  531.     kSize, kSize, GL_RED,
  532.     GL_FLOAT, kernel, kernel);
  533. #endif
  534. }
  535.  
  536. void
  537. toggle(int *param, char *msg)
  538. {
  539.   *param = !*param;
  540.   if (msg)
  541.     printf("%s == %d\n", msg, *param);
  542.   drawFrame(frame);
  543. }
  544.  
  545. void
  546. changePassCount(int delta)
  547. {
  548.   passes += delta;
  549.   if (passes < 0)
  550.     passes = 0;
  551.   printf("number of passes == %d\n", passes);
  552. }
  553.  
  554. void
  555. resize(int w, int h)
  556. {
  557.   winWidth = w;
  558.   winHeight = h;
  559.   pixels = realloc(pixels, (winWidth + 4) * (winHeight + 4));
  560.   glViewport(0, 0, winWidth, winHeight);
  561. }
  562.